
#include <sys/epoll.h>
// C++ STL
#include <functional>
#include <memory>
#include <string>
using namespace std;

#include "Timestamp.hpp"

#ifndef CHANNEL_HPP
#define CHANNEL_HPP

namespace tulun
{
    // static const int kNew = -1;
    // static const int kAdded = 1;
    // static const int kDeleted = 2;
    class EventLoop;
    class Channel
    {
    public:
        using EventCallback = std::function<void(void)>;
        using ReadEventCallback = std::function<void(tulun::Timestamp)>;

    private:
        static const int kNoneEvent;
        static const int kReadEvent;
        static const int kWriteEvent;

    private:
        EventLoop *loop_;
        const int fd_;
        int events_;
        int revents_;
        int index_;

        std::weak_ptr<void> tie_;

        bool tied_;
        bool eventHeadling_;
        bool addedToLoop_;

        ReadEventCallback readCallback_;
        EventCallback writeCallback_;
        EventCallback closeCallback_;
        EventCallback errorCallback_;

        void update();
        void handleEventWithGuard(const Timestamp &receiveTime);

    public:
        void handleEvent(const Timestamp &receiveTime);
        Channel(EventLoop *loop, int fd);
        ~Channel();
        void remove();
        int index() const { return index_; }
        void set_Index(const int index) { index_ = index; }

        std::string indexToString() const
        {
            std::string res("non");
            switch (index_)
            {
            case -1:
                res = "kNew";
                break;
            case 1:
                res = "kAdded";
                break;
            case 2:
                res = "kDeleted";
                break;
            }
            return res;
        }
        void setReadCallback(const ReadEventCallback &cb)
        {
            readCallback_ = cb;
        }
        void setWriteCallback(const EventCallback &cb)
        {
            writeCallback_ = cb;
        }
        void setCloseCallback(const EventCallback &cb)
        {
            closeCallback_ = cb;
        }
        void setErrorCallback(const EventCallback &cb)
        {
            errorCallback_ = cb;
        }

        int fd() const { return fd_; }
        int events() const { return events_; }
        void set_revents(int revt) { revents_ = revt; }
        bool isNoneEvent() const { return events_ == kNoneEvent; }

        void enableReading()
        {
            events_ |= kReadEvent;
            update();
        }
        void disableReading()
        {
            events_ &= ~kReadEvent;
            update();
        }
        void enableWriting()
        {
            events_ |= kWriteEvent;
            update();
        }
        void disableWriting()
        {
            events_ &= ~kWriteEvent;
            update();
        }
        void disableAll()
        {
            events_ = kNoneEvent;
            update();
        }
        bool isWriting() const { return events_ & kWriteEvent; }
        bool isReading() const { return events_ & kReadEvent; }

        EventLoop *ownerLoop() { return loop_; }
        std::string reventsToString() const;
        bool getEventHandling() const { return eventHeadling_; }
    };
} // namespace tulun

#endif